﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;

namespace HttpPublish
{
    class LocalTracker
    {
        private string _originalPath;
        private readonly PublishConfigration _config;

        public LocalTracker(PublishConfigration config)
        {
            _config = config;
        }

        /// <summary>
        /// Recursivly get a list of files specified by the config local path.
        /// </summary>
        /// <returns></returns>
        public Dictionary<string, TrackFileInfo> GetFiles()
        {
            if (!Directory.Exists(_config.Local))
            {
                return new Dictionary<string, TrackFileInfo>();
            }

            _originalPath = _config.Local;

            var list = GetFiles(_config.Local, _config.Extensions, _config.Exclude).ToDictionary(e => e.Name);
            return list;
        }

        private IEnumerable<TrackFileInfo> GetFiles(string path, ICollection<string> extensions, ICollection<string> excludeFolders )
        {
            var queue = new Queue<string>();
            queue.Enqueue(path);

            var regexPattern = @"\.*";

            if (extensions.Count > 0)
            {
                regexPattern = "";
                foreach (var p in extensions)
                {
                    if (!p.StartsWith("."))
                        throw new ArgumentException("Extensions must start with a period");

                    regexPattern += @"|" + Regex.Escape(p);
                }
                regexPattern = regexPattern.Substring(1);
            }

            var extensionTest = new Regex("(" + regexPattern + ")$", RegexOptions.IgnoreCase);

            while (queue.Count > 0)
            {
                path = queue.Dequeue();
                try
                {
                    foreach (var subDir in Directory.GetDirectories(path))
                    {
                        if (!excludeFolders.Contains(Path.GetFileName(subDir)))
                            queue.Enqueue(subDir);
                    }
                }
                catch (Exception ex)
                {
                    Log.Trace(ex.ToString());
                    continue;
                }

                string[] files;

                try
                {
                    files = Directory.GetFiles(path);
                }
                catch
                {
                    continue;
                }

                foreach (var fileName in files.Where(fileName => extensionTest.IsMatch(fileName)))
                {
                    var localName = fileName.Substring(_originalPath.Length+1).Replace(@"\", "/");
                    var fi = new FileInfo(fileName);
                    var ei = new TrackFileInfo
                                 {
                                     Name = localName,
                                     Size = (UInt64)fi.Length,
                                     Time = GetTime(fi.LastWriteTime),
                                     IsFolder = false
                                 };
                    yield return ei;
                }
            }
        }

        private static readonly DateTime TheBeginning = new DateTime(1970,1,1);

        private static UInt64 GetTime(DateTime time)
        {
            var t = time - TheBeginning;
            return (UInt64) (t.TotalMilliseconds + 0.5);
        }

        public static DateTime UtcToDateTime(UInt64 time)
        {
            return TheBeginning.AddMilliseconds(time).ToUniversalTime();
        }
    }
}
